package cn.qxq1.arthasdemo.controller;

import cn.qxq1.arthasdemo.model.DogModel;
import cn.qxq1.arthasdemo.model.UserModel;
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author zhangying
 * @date 2020-03-23
 * @description
 */
@RestController
@RequestMapping("user")
public class UserController {
    private static final Logger LOGGER = LoggerFactory.getLogger(UserController.class);
    private  List<UserModel> users;
    private Logger log = LoggerFactory.getLogger(UserController.class);

    @PostConstruct
    public void init(){
        users = new ArrayList<>();

        DogModel dog1 = new DogModel();
        dog1.setName("旺财1");
        DogModel dog2 = new DogModel();
        dog2.setName("旺财2");

        DogModel dog3 = new DogModel();
        dog3.setName("小黑1");
        DogModel dog4 = new DogModel();
        dog4.setName("小黑2");

        List<DogModel> dogs1 = new ArrayList<>();
        dogs1.add(dog1);
        dogs1.add(dog2);
        List<DogModel> dogs2 = new ArrayList<>();
        dogs2.add(dog3);
        dogs2.add(dog4);

        UserModel user1 = new UserModel();
        user1.setAge(10);
        user1.setName("张三");
        user1.setDogs(dogs1);

        UserModel user2 = new UserModel();
        user2.setAge(12);
        user2.setName("李四");
        user2.setDogs(dogs2);

        users.add(user1);
        users.add(user2);
    }

    /**
     * 传入Integer  返回String
     * @param age 年龄
     * @return 匹配到的人
     *          watch  cn.qxq1.arthasdemo.controller.UserController u1 "{params,returnObj}" -b -s -x 2
     */
    @GetMapping("u1")
    public String u1(Integer age){
        log.info("info | age is : {}",age);
        log.debug("debug | age is : {}",age);
        List<UserModel> collect = users.stream()
                .filter(user -> user.getAge().equals(age))
                .collect(Collectors.toList());
        return collect.isEmpty()?"未找到年龄为["+age+"]的用户":collect.toString();
    }

    /**
     * 传入引用类型 返回String
     * @param user 条件
     * @return 匹配到的人
     *          watch  cn.qxq1.arthasdemo.controller.UserController u2 "{params,returnObj}" -b -s -x 2
     *          指定引用类型的属性的条件表达式：
     *          watch  cn.qxq1.arthasdemo.controller.UserController u2 "{params,returnObj}" "params[0].age==10" -b -s -x 2
     */
    @GetMapping("u2")
    public String u2(UserModel user) {
        List<UserModel> collect = users.stream()
                .filter(u -> u.getAge().equals(user.getAge()))
                .collect(Collectors.toList());
        return collect.isEmpty()?"未找到年龄为["+user.getAge()+"]的用户":collect.toString();
    }

    /**
     * 传入应用类型，返回引用类型
     * @param userModel 条件
     * @return 匹配到的人
     *      watch  cn.qxq1.arthasdemo.controller.UserController u2 "{params,returnObj}" "params[0].age==10" -b -s -x 2
     *      监控该类下所有方法的入参：如果监控u3(),那么u3()及u3()内部调用其他带参数的方法也会被监控
     *      watch  cn.qxq1.arthasdemo.controller.UserController * "params" -b -x 2
     */
    @GetMapping("u3")
    public List<UserModel> u3(UserModel userModel){
        return users.stream()
                .filter(u -> u.getAge().equals(userModel.getAge()))
                .collect(Collectors.toList());
    }

    /**
     * 测试 trace ：方法内部调用路径，并输出方法路径上的每个节点上耗时
     * @param userModel 条件
     * @return 匹配到的人
     *          trace cn.qxq1.arthasdemo.controller.UserController u4
     *          trace cn.qxq1.arthasdemo.controller.UserController * 监控该类下所有方法
     */
    @GetMapping("u4")
    public List<UserModel> u4(UserModel userModel){
        //测试线上修改logger等级，先info，再debug
        LOGGER.info("user is : {}",JSON.toJSONString(userModel));
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("user is : {}",JSON.toJSONString(userModel));
        }
        trace1(userModel.getAge());
        //测试redefine,之前没有，后来加上
        System.out.println("redefine age is : "+userModel.getAge());
        return users.stream()
                .filter(u -> u.getAge().equals(userModel.getAge()))
                .collect(Collectors.toList());
    }

    private void trace1(int a){
        //测试tt 保存的为引用类型，无法记录方法中修改后的值
        a = a + 100;
        trace2(a);
    }

    /**
     * 测试 stack ：输出当前方法被调用的调用路径
     * @param b 入参
     *          监控trace2或该类下所有方法被调用的调用路径
     *             stack cn.qxq1.arthasdemo.controller.UserController trace2/*
     */
    private void trace2(int b){
        System.out.println("invoke trace2,  param is :"+b);
    }

    /**
     * 测试 grep
     * @return 所有人
     *      注意：| 和 grep 之间必须有空格，否则报错
     *          watch cn.qxq1.arthasdemo.controller.UserController u5 "{params,returnObj}" -s -x 2 | grep 12
     */
    @GetMapping("u5")
    public List<UserModel> u5(){
        return users;
    }

    /**
     * 测试 watch 抛出异常
     *              watch  cn.qxq1.arthasdemo.controller.UserController * "params" -e -x 2
     * @throws Exception
     */
    @GetMapping("u6")
    public List<UserModel> u6(UserModel model) throws Exception {
        System.out.printf("model is : %s", JSON.toJSONString(model));
        throw new Exception();
    }

    @GetMapping("u7")
    public String u7(UserModel model) {
        log.info("[info] param is : {}",JSON.toJSONString(model));
        //线上修改了日志中等级，如果logger没有使用到对应级别的appender(如:debug)，那么不会将日志输出到对应的日志文件中
        log.debug("[debug] is : {}",JSON.toJSONString(model));
        return "ok";
    }
}
